#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include "task.hpp"
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>
enum
{
    UsageError = 1,
    SubProNumError,
    PipeError
};

void Usage(const std::string &str)
{
    std::cout << "Usage:" << str << "[[subprocess-num]]" << std::endl;
}
class Channel
{
public:
    Channel(int wfd, pid_t sub_id, const std::string &name)
        : _wfd(wfd), _sub_id(sub_id), _name(name)
    {
    }
    void PrintDebug()
    {
        std::cout << "wfd:" << _wfd;
        std::cout << ",sub_id:" << _sub_id;
        std::cout << ",name:" << _name << std::endl;
    }
    int wfd()
    {
        return _wfd;
    }
    pid_t GetPid()
    {
      return _sub_id;  
    }

protected:
    int _wfd;      // 写端fd
    pid_t _sub_id; // 读端pid
    std::string _name;
};
class ProcessPool
{
public:
    ProcessPool(size_t size) : _size(size)
    {
    }
    void KillAll()
    {
        
        for(auto& ch : _Channels)
        {
            //1、让子进程退出
            close(ch.wfd());
            //2.回收子进程资源
            pid_t id = waitpid(ch.GetPid(),nullptr,0);
        }
    }
    int CreateProcess(work_t work)
    {
        for (size_t number = 0; number < _size; ++number)
        {
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
            {
                std::cout << "create pipe error!" << std::endl;
                exit(PipeError);
            }
            pid_t id = fork();
            if (id == 0)
            {
                // child "r"
                // 子进程把其他管道写端也继承下来了，需要进行处理
                //std::cout << "pid:" << getpid() <<  "close fd:";
                for(int i = 4 ; i <= pipefd[1] ; ++i)
                {
                    //std::cout << i <<" ";
                    close(i);
                }
                std::cout << std::endl;
                dup2(pipefd[0],0);
                work(pipefd[0]);
                exit(0);
            }
            // father "w"
            close(pipefd[0]);
            std::string name = "Channel-";
            name += std::to_string(number);
            _Channels.push_back(Channel(pipefd[1], id, name));
        }
        return 0;
    }
    int NextChannel()
    {
        static int next = 0;
        int c = next++;
        next %= _size;
        return c;
    }
    void SendTaskCode(int index, uint32_t code)
    {
        write(_Channels[index].wfd(),&code,sizeof(code));
    }
    void Debug()
    {
        for (auto &ch : _Channels)
        {
            ch.PrintDebug();
        }
    }

protected:
    size_t _size;
    std::vector<Channel> _Channels;
};
//./processpool [subprocess-num]
int main(int argc, char *argv[])
{
    // 1、准备工作
    if (argc != 2)
    {
        Usage(argv[0]);
        return UsageError;
    }
    int sub_process_num = std::stoi(argv[1]);
    if (sub_process_num < 1)
    {
        std::cout << "sub process num is less!" << std::endl;
        return SubProNumError;
    }

    // 2、创建管道及子进程
    ProcessPool pool(sub_process_num);
    pool.CreateProcess(worker);
    // pool.Debug();

    // 3、进程控制
    int cnt = 10;
    while (cnt--)
    {
        // a.负载均衡选择管道
        int next = pool.NextChannel();
        // b.选择任务
        uint32_t code = NextTask();
        // c.发送任务
        pool.SendTaskCode(next,code);
    }
    sleep(10);
    //4.进程回收
    pool.KillAll();

    // for (auto &ch : Channels)
    // {
    //     ch.PrintDebug();
    // }
    sleep(100);
    return 0;
}